import 'package:math_keyboard/src/foundation/node.dart';
import 'package:math_keyboard/src/foundation/extended_nodes.dart';
import 'package:math_keyboard/src/widgets/math_field.dart';

/// Handler for managing limit expressions (integrals, sums, products, limits).
class LimitExpressionHandler {
  /// Creates an integral expression with upper and lower limits and integrand.
  static void addIntegral(MathFieldEditingController controller) {
    final integral = createIntegral(controller.currentNode);
    
    // Add to current node
    controller.currentNode.removeCursor();
    controller.currentNode.addTeX(integral);
    
    // Move cursor to the lower limit (first argument)
    controller.currentNode = integral.lowerLimit!;
    controller.currentNode.courserPosition = 0;
    controller.currentNode.setCursor();
  }

  /// Creates a sum expression with upper and lower limits.
  static void addSum(MathFieldEditingController controller) {
    final sum = createSum(controller.currentNode);
    
    // Add to current node
    controller.currentNode.removeCursor();
    controller.currentNode.addTeX(sum);
    
    // Move cursor to the lower limit (first argument)
    controller.currentNode = sum.lowerLimit!;
    controller.currentNode.courserPosition = 0;
    controller.currentNode.setCursor();
  }

  /// Creates a product expression with upper and lower limits.
  static void addProduct(MathFieldEditingController controller) {
    final product = createProduct(controller.currentNode);
    
    // Add to current node
    controller.currentNode.removeCursor();
    controller.currentNode.addTeX(product);
    
    // Move cursor to the lower limit (first argument)
    controller.currentNode = product.lowerLimit!;
    controller.currentNode.courserPosition = 0;
    controller.currentNode.setCursor();
  }

  /// Creates a limit expression with variable and approach value.
  static void addLimit(MathFieldEditingController controller) {
    final limit = createLimit(controller.currentNode);
    
    // Add to current node
    controller.currentNode.removeCursor();
    controller.currentNode.addTeX(limit);
    
    // Move cursor to the limit expression (first argument)
    controller.currentNode = limit.lowerLimit!;
    controller.currentNode.courserPosition = 0;
    controller.currentNode.setCursor();
  }

  /// Creates an integral structure.
  static TeXLimitExpression createIntegral(TeXNode parent) {
    return TeXLimitExpression(
      r'\int',
      parent,
      lowerLimit: TeXNode(null),
      upperLimit: TeXNode(null),
      bodyNode: TeXNode(null),
      hasBody: true,
    );
  }

  /// Creates a sum structure.
  static TeXLimitExpression createSum(TeXNode parent) {
    return TeXLimitExpression(
      r'\sum',
      parent,
      lowerLimit: TeXNode(null),
      upperLimit: TeXNode(null),
      hasBody: false,
    );
  }

  /// Creates a product structure.
  static TeXLimitExpression createProduct(TeXNode parent) {
    return TeXLimitExpression(
      r'\prod',
      parent,
      lowerLimit: TeXNode(null),
      upperLimit: TeXNode(null),
      hasBody: false,
    );
  }

  /// Creates a limit structure.
  static TeXLimitExpression createLimit(TeXNode parent) {
    return TeXLimitExpression(
      r'\lim',
      parent,
      lowerLimit: TeXNode(null),
      hasBody: false,
    );
  }

  /// Creates a custom limit expression with the specified symbol.
  static TeXLimitExpression createCustomLimitExpression(
    String symbol,
    TeXNode parent, {
    bool hasLowerLimit = true,
    bool hasUpperLimit = false,
    bool hasBody = false,
  }) {
    return TeXLimitExpression(
      symbol,
      parent,
      lowerLimit: hasLowerLimit ? TeXNode(null) : null,
      upperLimit: hasUpperLimit ? TeXNode(null) : null,
      bodyNode: hasBody ? TeXNode(null) : null,
      hasBody: hasBody,
    );
  }

  /// Creates a definite integral with specific limits.
  static TeXLimitExpression createDefiniteIntegral(
    TeXNode parent,
    String lowerLimit,
    String upperLimit,
  ) {
    final integral = createIntegral(parent);
    
    // Set the limits
    integral.lowerLimit!.addTeX(TeXLeaf(lowerLimit));
    integral.upperLimit!.addTeX(TeXLeaf(upperLimit));
    
    return integral;
  }

  /// Creates a sum with specific limits.
  static TeXLimitExpression createSumWithLimits(
    TeXNode parent,
    String lowerLimit,
    String upperLimit,
  ) {
    final sum = createSum(parent);
    
    // Set the limits
    sum.lowerLimit!.addTeX(TeXLeaf(lowerLimit));
    sum.upperLimit!.addTeX(TeXLeaf(upperLimit));
    
    return sum;
  }

  /// Creates a product with specific limits.
  static TeXLimitExpression createProductWithLimits(
    TeXNode parent,
    String lowerLimit,
    String upperLimit,
  ) {
    final product = createProduct(parent);
    
    // Set the limits
    product.lowerLimit!.addTeX(TeXLeaf(lowerLimit));
    product.upperLimit!.addTeX(TeXLeaf(upperLimit));
    
    return product;
  }

  /// Creates a limit with specific approach.
  static TeXLimitExpression createLimitWithApproach(
    TeXNode parent,
    String variable,
    String approachValue,
  ) {
    final limit = createLimit(parent);
    
    // Set the limit expression (e.g., "x \to 0")
    limit.lowerLimit!.addTeX(TeXLeaf(variable));
    limit.lowerLimit!.addTeX(TeXLeaf(r' \to '));
    limit.lowerLimit!.addTeX(TeXLeaf(approachValue));
    
    return limit;
  }

  /// Validates a limit expression structure.
  static bool validateLimitExpression(TeXLimitExpression expr) {
    // Check if required components are present
    switch (expr.expression) {
      case r'\int':
        return expr.hasLowerLimit && 
               expr.hasUpperLimit && 
               expr.hasBody &&
               expr.bodyNode != null;
      case r'\sum':
      case r'\prod':
        return expr.hasLowerLimit && expr.hasUpperLimit;
      case r'\lim':
        return expr.hasLowerLimit;
      default:
        return true; // Custom expressions are assumed valid
    }
  }

  /// Gets the navigation order for a limit expression.
  static List<TeXNode> getNavigationOrder(TeXLimitExpression expr) {
    final order = <TeXNode>[];
    
    // Add nodes in logical order: lower limit -> upper limit -> body
    if (expr.hasLowerLimit && expr.lowerLimit != null) {
      order.add(expr.lowerLimit!);
    }
    if (expr.hasUpperLimit && expr.upperLimit != null) {
      order.add(expr.upperLimit!);
    }
    if (expr.hasBody && expr.bodyNode != null) {
      order.add(expr.bodyNode!);
    }
    
    return order;
  }

  /// Gets the display name for a limit expression type.
  static String getDisplayName(String symbol) {
    switch (symbol) {
      case r'\int':
        return 'Integral';
      case r'\sum':
        return 'Sum';
      case r'\prod':
        return 'Product';
      case r'\lim':
        return 'Limit';
      default:
        return symbol;
    }
  }

  /// Checks if a symbol represents a limit expression.
  static bool isLimitExpression(String symbol) {
    return [r'\int', r'\sum', r'\prod', r'\lim'].contains(symbol);
  }

  /// Creates common mathematical limit expressions.
  static Map<String, TeXLimitExpression Function(TeXNode)> get commonExpressions => {
    'integral': createIntegral,
    'sum': createSum,
    'product': createProduct,
    'limit': createLimit,
  };

  /// Creates specialized limit expressions.
  static Map<String, TeXLimitExpression Function(TeXNode)> get specializedExpressions => {
    'double_integral': (parent) => createCustomLimitExpression(r'\iint', parent, hasBody: true),
    'triple_integral': (parent) => createCustomLimitExpression(r'\iiint', parent, hasBody: true),
    'contour_integral': (parent) => createCustomLimitExpression(r'\oint', parent, hasBody: true),
    'union': (parent) => createCustomLimitExpression(r'\bigcup', parent, hasLowerLimit: true, hasUpperLimit: true),
    'intersection': (parent) => createCustomLimitExpression(r'\bigcap', parent, hasLowerLimit: true, hasUpperLimit: true),
    'supremum': (parent) => createCustomLimitExpression(r'\sup', parent, hasLowerLimit: true),
    'infimum': (parent) => createCustomLimitExpression(r'\inf', parent, hasLowerLimit: true),
    'maximum': (parent) => createCustomLimitExpression(r'\max', parent, hasLowerLimit: true),
    'minimum': (parent) => createCustomLimitExpression(r'\min', parent, hasLowerLimit: true),
  };
}